"""
Author: runyu.ma

frontend.py
"""

from .core.dslc_symbol_table import build_default_symtab
from .core.dslc_parser import build_default_parser
from .core.dslc_lexer import build_default_lexer
from .core.dslc_parser import Number, Identifier, UnaryOp, BinaryOp, BlockOp, ASTNode, String
from .interpret import evaluation
from .passes import *

# 打印 AST 成树状结构
def print_ast(node, indent=0):
    pad = ' ' * indent

    if isinstance(node, Number):
        print(f"{pad}Number({node.value})")
    
    elif isinstance(node, String):
        print(f"{pad}String({node.value})")

    elif isinstance(node, Identifier):
        print(f"{pad}Ident({node.name})")

    elif isinstance(node, UnaryOp):
        print(f"{pad}UnaryOp(op={node.op})")
        print_ast(node.x, indent + 2)

    elif isinstance(node, BinaryOp):
        print(f"{pad}BinaryOp(op={node.op})")
        print_ast(node.l, indent + 2)
        print_ast(node.r, indent + 2)

    elif isinstance(node, BlockOp):
        print(f"{pad}BlockOp")
        for op in node.oplist:
            print_ast(op, indent + 2)

    else:
        # 通用回退：尝试遍历 __dict__ 或列表
        cls = node.__class__.__name__
        print(f"{pad}{cls}")
        for attr, val in vars(node).items():
            if isinstance(val, ASTNode):
                print_ast(val, indent + 2)
            elif isinstance(val, list):
                for item in val:
                    if isinstance(item, ASTNode):
                        print_ast(item, indent + 2)

# 打印 AST 成树状结构
def fsave_ast(fil, node, indent=0):
    pad = ' ' * indent

    if isinstance(node, Number):
        fil.write(f"{pad}Number({node.value})\n")
    
    elif isinstance(node, String):
        fil.write(f"{pad}String({node.value})\n")

    elif isinstance(node, Identifier):
        fil.write(f"{pad}Ident({node.name})\n")

    elif isinstance(node, UnaryOp):
        fil.write(f"{pad}UnaryOp(op={node.op})\n")
        fsave_ast(fil, node.x, indent + 2)

    elif isinstance(node, BinaryOp):
        fil.write(f"{pad}BinaryOp(op={node.op})\n")
        fsave_ast(fil, node.l, indent + 2)
        fsave_ast(fil, node.r, indent + 2)

    elif isinstance(node, BlockOp):
        fil.write(f"{pad}BlockOp\n")
        for op in node.oplist:
            fsave_ast(fil, op, indent + 2)

    else:
        # 通用回退：尝试遍历 __dict__ 或列表
        cls = node.__class__.__name__
        fil.write(f"{pad}{cls}\n")
        for attr, val in vars(node).items():
            if isinstance(val, ASTNode):
                fsave_ast(fil, val, indent + 2)
            elif isinstance(val, list):
                for item in val:
                    if isinstance(item, ASTNode):
                        fsave_ast(fil, item, indent + 2)


def string_to_ast(s: str):
    '''将字符串转成ast'''

    lexer = build_default_lexer()
    tokens = lexer.tokenize(s)

    parser = build_default_parser(tokens)
    ast = parser.parse()

    stab = build_default_symtab()
    #去掉注释
    ast = BlockOp([op for op in ast.oplist if isinstance(op, BlockOp)])
    #逗号展开
    ast = traversal_ast_to(stab, ast,\
        lambda _, x: isinstance(x, BinaryOp) and x.op == ',', flatten_nested_binary_comma)
    ast = traversal_ast_to(stab, ast,\
        lambda _, x: isinstance(x, BlockOp), append_attr_pass)
    #处理变量定义的表达式
    ast = merge_block_content(ast, merge_var_name_pass)
    ast = traversal_ast_to(stab, ast,\
        lambda _, x: is_var_define_block(x), unary_var_define_pass)
    #合并if

    ast = merge_nested_block_content(ast, merge_loop_cond_pass)

    ast = merge_nested_block_content(ast, merge_while_cond_pass)

    ast = merge_nested_block_content(ast, merge_if_cond_pass)
    ast = merge_nested_block_content(ast, merge_else_cond_pass)

    traversal_ast_to(stab, ast,\
        lambda s, x: is_else_if_keyword(x), merge_else_if_keyword_pass)

    #ast = evaluation(stab, ast)

    traversal_ast_to(stab, ast,\
        lambda s, x: isinstance(x, BinaryOp)\
            and x.op == '!', builtin_insta_pass)

    traversal_ast_to(stab, ast,\
        lambda s, x: isinstance(x, BinaryOp)\
            and x.op == '!', builtin_macro_pass)

    #ast = evaluation(stab, ast)

    #需要evaluation先把数组取值$等op处理了才能确认某些参数
    ast = traversal_ast_to(stab, ast,\
        lambda s, x: isinstance(x, String) and isinstance(x.parent, BinaryOp), meta_pystr_in_node)

    ast = traversal_ast_to(stab, ast,\
        lambda s, x: is_macro_define_block(x), macro_define_pass)

    ast = merge_block_content(ast, merge_marco_param_pass)

    ast = traversal_ast_to(stab, ast,\
        lambda s, x: is_macro_expand_block(x), macro_expand_pass)

    #ast = evaluation(stab, ast)
    return ast
